home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / PVIEW95.PAK / PROCTHRD.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  18KB  |  523 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   procthrd.c
  9. //
  10. //  PURPOSE:  Implements process and thread enumeration/manipulation
  11. //            functions. 
  12. //
  13. //  FUNCTIONS:
  14. //    InitToolhelp32        - Dynamically resolves addresses of 32-bit 
  15. //                            Toolhelp functions
  16. //    RefreshThreadList     - Enumerates and displays active threads
  17. //    RefreshProcessList    - Enumerates and displays active processes
  18. //    GetProcessModule      - Gets information about a specific module in 
  19. //                            a specified process
  20. //    KillProcess           - Kills the specified process
  21. //    GetModuleNameFromExe  - Returns a Win16 app/DLL's module name from
  22. //                            its executable file.
  23. //   
  24. //
  25. //  COMMENTS:
  26. //
  27.  
  28. #include <windows.h>
  29. #include <tlhelp32.h>              // Required for ToolHelp32 functions
  30. #include <commctrl.h>
  31. #include "procthrd.h"
  32. #include "listview.h"
  33. #include "globals.h"
  34.  
  35.  
  36. //-------------------------------------------------------------------------
  37. // Type definitions for functions pointers used to call 32-bit Toolhelp 
  38. // functions.
  39. typedef BOOL (WINAPI *MODULEWALK)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
  40. typedef BOOL (WINAPI *THREADWALK)(HANDLE hSnapshot, LPTHREADENTRY32 lpte);
  41. typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
  42. typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
  43.  
  44.  
  45. //-------------------------------------------------------------------------
  46. // File-scope globals.  These pointers are declared because we have to
  47. // dynamically link to these funtions.  They are exported only by the
  48. // Windows 95 KERNEL32.DLL.  Explicitly linking to them will make this
  49. // application unloadable on Windows NT and will produce an ugly system
  50. // dialog that isn't nice for end-users to see.
  51.  
  52. static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
  53. static MODULEWALK  pModule32First  = NULL;
  54. static MODULEWALK  pModule32Next   = NULL;
  55. static PROCESSWALK pProcess32First = NULL;
  56. static PROCESSWALK pProcess32Next  = NULL;
  57. static THREADWALK  pThread32First  = NULL;
  58. static THREADWALK  pThread32Next   = NULL;
  59.  
  60.  
  61. //-------------------------------------------------------------------------
  62. // Local function prototypes.
  63.  
  64. BOOL GetProcessModule (DWORD dwPID, DWORD dwModuleID, LPMODULEENTRY32 lpMe32,
  65.                        DWORD cbMe32);
  66. BOOL GetModuleNameFromExe (LPCSTR szFileName, LPSTR szModuleName, WORD cbLen);
  67.  
  68.  
  69. //
  70. //  FUNCTION: InitToolhelp32(void)
  71. //
  72. //  PURPOSE:  Initializes pointers to the 32-bit Toolhelp APIs that are
  73. //            exported only by the Windows 95 KERNEL32.DLL.
  74. //            
  75. //  PARAMETERS:
  76. //    None.
  77. //
  78. //  RETURN VALUE:
  79. //    TRUE if addresses of all needed 32-bit Toolhelp functions were 
  80. //    retrieved.
  81. //    FALSE if we couldn't get the address of even one needed 32-bit 
  82. //    Toolhelp function
  83. //
  84. //  COMMENTS:
  85. //    This function is needed to initialize the function pointers to the
  86. //    32-bit Toolhelp functions because at this time, only the Windows 95
  87. //    KERNEL32.DLL exports them.  If we did not dynamically resolve the
  88. //    addresses of these functions, this application would not even load
  89. //    on anything but Windows 95.
  90. //
  91. //    In the case of this sample, this function is called in InitApplication
  92. //    which will prevent this application from even running if it can't 
  93. //    access the necessary functions.
  94. //
  95.  
  96. BOOL InitToolhelp32 (void)
  97. {
  98.      BOOL   bRet;
  99.      HANDLE hKernel;
  100.  
  101.  
  102.     // Obtain a module handle to KERNEL so that we can get the addresses of 
  103.     // the 32-bit Toolhelp functions we need.
  104.  
  105.     hKernel = GetModuleHandle("KERNEL32.DLL");
  106.  
  107.     if (hKernel)
  108.     {
  109.         pCreateToolhelp32Snapshot =
  110.           (CREATESNAPSHOT)GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
  111.  
  112.         pModule32First  = (MODULEWALK)GetProcAddress(hKernel, 
  113.                                                       "Module32First");
  114.         pModule32Next   = (MODULEWALK)GetProcAddress(hKernel, 
  115.                                                      "Module32Next");
  116.  
  117.         pProcess32First = (PROCESSWALK)GetProcAddress(hKernel, 
  118.                                                       "Process32First");
  119.         pProcess32Next  = (PROCESSWALK)GetProcAddress(hKernel, 
  120.                                                       "Process32Next");
  121.  
  122.         pThread32First  = (THREADWALK)GetProcAddress(hKernel, 
  123.                                                      "Thread32First");
  124.         pThread32Next   = (THREADWALK)GetProcAddress(hKernel, 
  125.                                                      "Thread32Next");
  126.  
  127.         // All of our addresses must be non-NULL in order for us to be
  128.         // successful.  If even one of these addresses is NULL, then we
  129.         // must fail because we won't be able to walk one of the lists
  130.         // we need to.  
  131.         bRet =  pModule32First && pModule32Next  && pProcess32First &&
  132.                 pProcess32Next && pThread32First && pThread32Next &&
  133.                 pCreateToolhelp32Snapshot;
  134.     }
  135.     else
  136.         bRet = FALSE;  // Couldn't even get a module handle to KERNEL.
  137.  
  138.     return bRet;
  139. }
  140.  
  141.  
  142. //
  143. //  FUNCTION: RefreshThreadList(HWND, DWORD)
  144. //
  145. //  PURPOSE:  Enumerates and displays the list of threads owned by a 
  146. //            specified process.
  147. //
  148. //  PARAMETERS:
  149. //    hListView    - Handle of the listview that lists thread information
  150. //    dwOwnerPID   - ID of process whose threads we will list
  151. //
  152. //  RETURN VALUE:
  153. //    TRUE if the threads were successfully enumerated and listed
  154. //     FALSE if the threads could not be enumerated or listed
  155. //
  156. //  COMMENTS:
  157. //
  158.  
  159. BOOL RefreshThreadList (HWND hListView, DWORD dwOwnerPID)
  160. {
  161.      HANDLE        hThreadSnap;
  162.      BOOL          bRet;
  163.     THREADENTRY32 te32        = {0};
  164.  
  165.     // Take a snapshot of all threads currently in the system.
  166.     hThreadSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  167.     if (hThreadSnap == (HANDLE)-1)
  168.         return (FALSE);
  169.  
  170.     // Clear the current contents of the thread list view (which are now old).
  171.     ListView_DeleteAllItems(g_hwndThread);
  172.  
  173.     // Size of the THREADENTRY32 structure must be filled out before use.
  174.     te32.dwSize = sizeof(THREADENTRY32);
  175.  
  176.     // Walk thread snapshot to find all threads of the process we want.
  177.     // If the thread belongs to the process we want, add its information  
  178.     // to the display list.
  179.     if (pThread32First(hThreadSnap, &te32))
  180.     {
  181.         do 
  182.         {   
  183.             if (te32.th32OwnerProcessID == dwOwnerPID)
  184.             {   
  185.                 TINFO ti;
  186.  
  187.                 ti.tid        = te32.th32ThreadID;
  188.                 ti.pidOwner   = te32.th32OwnerProcessID;
  189.                 ti.tpDeltaPri = te32.tpDeltaPri;
  190.                 ti.tpBasePri  = te32.tpBasePri;
  191.  
  192.                 AddThreadItem(hListView, ti);
  193.             }
  194.         }
  195.         while (pThread32Next(hThreadSnap, &te32));
  196.         bRet = TRUE;
  197.     }
  198.     else
  199.         bRet = FALSE;          // Couldn't walk the list of threads.
  200.  
  201.     // Don't forget to clean up the snapshot object...
  202.     CloseHandle (hThreadSnap);
  203.  
  204.     return (bRet);
  205. }
  206.  
  207.  
  208. //
  209. //  FUNCTION: RefreshProcessList(HWND)
  210. //
  211. //  PURPOSE:  Enumerates and displays the list of processes.
  212. //
  213. //  PARAMETERS:
  214. //    hListView   - Handle of the listview that lists process information
  215. //
  216. //  RETURN VALUE:
  217. //    TRUE if the processes were successfully enumerated and listed
  218. //     FALSE if the processes could not be enumerated or listed
  219. //
  220. //  COMMENTS:
  221. //     Refreshes the list of processes by making a process snapshot and
  222. //    putting info about each process into the listview control specifed by
  223. //    hListView.
  224.  
  225. BOOL RefreshProcessList (HWND hListView)
  226. {
  227.      HANDLE         hProcessSnap;
  228.      BOOL           bRet;
  229.     PROCESSENTRY32 pe32         = {0};
  230.  
  231.     // Take a snapshot of all processes currently in the system.
  232.     hProcessSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  233.     if (hProcessSnap == (HANDLE)-1)
  234.         return (FALSE);
  235.  
  236.     // Clear the current contents of the process list view (which are now old).
  237.     ListView_DeleteAllItems(g_hwndProcess);
  238.  
  239.     // Size of the PROCESSENTRY32 structure must be filled out before use.
  240.     pe32.dwSize = sizeof(PROCESSENTRY32);
  241.  
  242.     // Walk the snapshot of processes and for each process, get information
  243.     // to display.
  244.     if (pProcess32First(hProcessSnap, &pe32))
  245.     {
  246.           BOOL          bGotModule;
  247.         MODULEENTRY32 me32       = {0};
  248.           PINFO         pi         = {{0}, 0};
  249.  
  250.           do
  251.           {
  252.             bGotModule = GetProcessModule(pe32.th32ProcessID, 
  253.                                           pe32.th32ModuleID, 
  254.                                           &me32, 
  255.                                           sizeof(MODULEENTRY32));
  256.             if (bGotModule)
  257.             {
  258.                 HANDLE hProcess;
  259.  
  260.                 // Get actual priority class
  261.                 hProcess = OpenProcess (PROCESS_ALL_ACCESS, 
  262.                                         FALSE, 
  263.                                         pe32.th32ProcessID);
  264.                      pi.dwPriorityClass = GetPriorityClass (hProcess);
  265.                 CloseHandle (hProcess);
  266.  
  267.                 // Get process's base priority value
  268.                 pi.pcPriClassBase = pe32.pcPriClassBase;
  269.                 pi.pid            = pe32.th32ProcessID;
  270.                 pi.cntThreads     = pe32.cntThreads;
  271.  
  272.                 lstrcpy(pi.szFullPath, pe32.szExeFile);
  273.  
  274.                 // Test to see if the app is a Win16 or Win32 app.  If the
  275.                 // file name returned in the PROCESSENTRY32 and MODULEENTRY32
  276.                 // structures are equal, then we have a Win32 app, otherwise,
  277.                 // we have a Win16 app.  
  278.  
  279.                 if (!lstrcmpi (pe32.szExeFile, me32.szExePath))
  280.                 {
  281.                     // Win32 app, use MODULENETRY32 module name
  282.                     lstrcpy(pi.szModName, me32.szModule);
  283.                     pi.uAppType = EXETYPE_32BIT;
  284.                 }
  285.                 else
  286.                 {
  287.                     // Win16 app, get module name out of EXE header of file
  288.                     if (!GetModuleNameFromExe (pe32.szExeFile, pi.szModName,
  289.                                                sizeof(pi.szModName)))
  290.                     {
  291.                         // If we can't get the module name for some reason, at
  292.                         // least put something in the module name.
  293.                         lstrcpy(pi.szModName, me32.szModule);
  294.                     }
  295.                     pi.uAppType = EXETYPE_16BIT;
  296.                 }
  297.                 AddProcessItem(hListView, pi);
  298.             }
  299.         }
  300.         while (pProcess32Next(hProcessSnap, &pe32));
  301.         bRet = TRUE;
  302.     }
  303.     else
  304.         bRet = FALSE;    // Couldn't walk the list of processes.
  305.  
  306.     // Don't forget to clean up the snapshot object...
  307.     CloseHandle (hProcessSnap);
  308.     return (bRet);
  309. }
  310.  
  311.  
  312. //
  313. //  FUNCTION: GetProcessModule(DWORD, DWORD, LPMODULEENTRY32, DWORD)
  314. //
  315. //  PURPOSE:  Given a Process ID and module ID, return its module information.
  316. //
  317. //  PARAMETERS:
  318. //    dwPID      - ID of process that owns the module we want information 
  319. //                 about.
  320. //    dwModuleID - ToolHelp32 ID of the module within the process
  321. //    lpMe32     - Structure to return data about the module we want
  322. //    cbMe32     - Size of the buffer pointed to by lpMe32--to make sure we 
  323. //                 don't copy too much data into lpMe32.
  324. //
  325. //  RETURN VALUE:
  326. //    TRUE if it returns information about the specifed module.
  327. //    FALSE if it could not enumerate the modules in the process, or the
  328. //          module is not found in the process.
  329. //
  330. //  COMMENTS:
  331. //
  332.  
  333. BOOL GetProcessModule (DWORD           dwPID, 
  334.                        DWORD           dwModuleID, 
  335.                        LPMODULEENTRY32 lpMe32, 
  336.                        DWORD           cbMe32)
  337. {   
  338.      BOOL          bRet;
  339.     BOOL          bFound      = FALSE;
  340.      HANDLE        hModuleSnap;
  341.     MODULEENTRY32 me32        = {0};
  342.  
  343.     // Take a snapshot of all modules in the specified process.
  344.     hModuleSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
  345.     if (hModuleSnap == (HANDLE)-1)
  346.         return (FALSE);
  347.  
  348.     // Size of the MODULEENTRY32 structure must be initialized before use!
  349.     me32.dwSize = sizeof(MODULEENTRY32);
  350.  
  351.     // Walk the module list of the process and find the module we are 
  352.     // interested in.  Then, copy the information to the buffer pointed to
  353.     // by lpMe32 so that we can return it to the caller.
  354.     if (pModule32First(hModuleSnap, &me32))
  355.     {
  356.         do 
  357.         {
  358.             if (me32.th32ModuleID == dwModuleID)
  359.             {
  360.                 CopyMemory (lpMe32, &me32, cbMe32);
  361.                 bFound = TRUE;
  362.             }
  363.         }
  364.         while (!bFound && pModule32Next(hModuleSnap, &me32));
  365.  
  366.         bRet = bFound;   // If this sets bRet to FALSE, then dwModuleID 
  367.                          // no longer exsists in the specified process.
  368.     }
  369.     else
  370.         bRet = FALSE;    // Couldn't walk module list.
  371.  
  372.     // Don't forget to clean up the snapshot object...
  373.     CloseHandle (hModuleSnap);
  374.  
  375.     return (bRet);
  376. }
  377.  
  378.  
  379. //
  380. //  FUNCTION: KillProcess(DWORD)
  381. //
  382. //  PURPOSE:  To kills a specified process
  383. //
  384. //  PARAMETERS:
  385. //    dwPID      - Process ID of the process to kill
  386. //
  387. //  RETURN VALUE:
  388. //    TRUE if the specified process was killed
  389. //    FALSE if it wasn't killed.
  390. //
  391. //  COMMENTS:
  392. //    KillProcess does not return until the process is terminated.
  393. //
  394.  
  395. BOOL KillProcess (DWORD dwPID)
  396. {
  397.      BOOL   bRet;
  398.      HANDLE hProcess;
  399.  
  400.     // Open the process to obtain a handle to it.  If we get a handle,
  401.     // try to terminate the process.  Wait until the process is really
  402.      // dead before returning.
  403.     hProcess = OpenProcess (PROCESS_TERMINATE, FALSE, dwPID);
  404.     if (hProcess != NULL)
  405.     {    
  406.         bRet = TerminateProcess (hProcess, 0xFFFFFFFF);
  407.  
  408.         // Don't want to wait if the terminate fails.  If the
  409.         // process is still running and we can't terminate it,
  410.         // then waiting for it would cause this process to stop
  411.         // execution.
  412.         if (bRet)
  413.             WaitForSingleObject(hProcess, INFINITE);
  414.  
  415.         CloseHandle (hProcess);
  416.     }
  417.     else
  418.         bRet = FALSE;
  419.  
  420.     return (bRet);
  421. }
  422.  
  423.  
  424. //
  425. //  FUNCTION: GetModuleNameFromExe(LPCSTR, LPSTR, WORD)
  426. //
  427. //  PURPOSE:  Retrieves the module name of a Win16 app or DLL from its
  428. //            excutable file.
  429. //
  430. //  PARAMETERS:
  431. //    szFileName   - Executable file (.EXE or .DLL) from which to retrieve 
  432. //                   module name
  433. //    szModuleName - Points to buffer that receives the module name
  434. //    cbLen        - Specifies maximum length of szModuleName including NULL
  435. //
  436. //  RETURN VALUE:
  437. //    TRUE if the module name was succesfully copied into szModuleName.
  438. //    FALSE if it wasn't killed.
  439. //
  440. //  COMMENTS:
  441. //    Works for Win16 New Executable files only.
  442. //
  443.  
  444. BOOL GetModuleNameFromExe (LPCSTR szFileName, LPSTR szModuleName, WORD cbLen)
  445. {
  446.     BOOL              bResult;
  447.     HANDLE            hFile        = NULL;
  448.     HANDLE            hFileMapping = NULL;
  449.      PIMAGE_OS2_HEADER pNEHdr;
  450.     PIMAGE_DOS_HEADER pDosExeHdr   = NULL;
  451.  
  452.     // Open the file as read-only.  (This file may be opened already by the
  453.     // system if it is an application or DLL that is currently loaded.)
  454.     // Create a read-only file mapping and map a read-only view of the file.
  455.     // If we can't open the file for some reason, then return FALSE.
  456.   
  457.     hFile = CreateFile(szFileName,
  458.                        GENERIC_READ,
  459.                        FILE_SHARE_READ|FILE_SHARE_WRITE,
  460.                        NULL,
  461.                        OPEN_EXISTING,
  462.                        0,
  463.                        NULL);
  464.  
  465.     if (hFile == INVALID_HANDLE_VALUE)
  466.         return FALSE;
  467.  
  468.     hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  469.     if (hFileMapping == NULL)
  470.     {
  471.         CloseHandle(hFile);
  472.         return FALSE;
  473.     }
  474.  
  475.     pDosExeHdr = (PIMAGE_DOS_HEADER)MapViewOfFile (hFileMapping,
  476.                                                    FILE_MAP_READ,
  477.                                                    0,
  478.                                                    0,
  479.                                                    0);
  480.     if (!pDosExeHdr)
  481.     {
  482.         CloseHandle(hFileMapping);
  483.         CloseHandle(hFile);
  484.         return FALSE;
  485.     }
  486.  
  487.     __try
  488.     {
  489.         // Go to the beginning of the NE header.
  490.         pNEHdr =
  491.            (PIMAGE_OS2_HEADER)((LPSTR)pDosExeHdr + pDosExeHdr -> e_lfanew);
  492.  
  493.         // Check to make sure that the file has DOS and NE EXE headers
  494.         if (pDosExeHdr -> e_magic == IMAGE_DOS_SIGNATURE
  495.             && pNEHdr -> ne_magic == IMAGE_OS2_SIGNATURE)
  496.         {
  497.             lstrcpyn (szModuleName, (LPSTR)pNEHdr + pNEHdr -> ne_restab +1,  
  498.                       min((BYTE)*((LPSTR)pNEHdr + pNEHdr -> ne_restab) + 1, 
  499.                           cbLen));
  500.             bResult = TRUE;
  501.         }
  502.         else
  503.             bResult = FALSE;
  504.  
  505.     }
  506.     __except (EXCEPTION_EXECUTE_HANDLER)
  507.     {
  508.         // If an access violation occurs in the try block, we know the file
  509.         // is not a NE file because it is too small to have a NE header, or
  510.         // the offset of the NE header isn't close to being correct.
  511.         bResult = FALSE;
  512.     }
  513.  
  514.     // Clean up file mapping, all views of file mapping, and close the
  515.     // file.
  516.     UnmapViewOfFile(pDosExeHdr);
  517.     CloseHandle(hFileMapping);
  518.     CloseHandle(hFile);
  519.  
  520.     return bResult;
  521. }
  522.  
  523.